package com.google.code.pdfbrick.splitter;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.code.pdfbrick.engine.FileOperator;
import com.google.code.pdfbrick.engine.PDFOperator;
import com.google.code.pdfbrick.engine.base.Validatable;
import com.google.code.pdfbrick.engine.command.FilePageRange;
import com.google.code.pdfbrick.engine.command.PageRange;
import com.google.code.pdfbrick.engine.command.ParsableCommand;
import com.google.code.pdfbrick.engine.exception.CommandExecuteException;
import com.google.code.pdfbrick.engine.exception.CommandParseException;
import com.google.code.pdfbrick.engine.exception.CommandValidateException;
import com.google.code.pdfbrick.engine.exception.PDFOperationException;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfReader;

/**
 * @author Johny Huang
 * @date 2009-3-7
 */
public class SplitCommand implements ParsableCommand,Validatable {

	private static final Log log = LogFactory.getLog(SplitCommand.class);

	private static final SplitCommandParser PARASER=new SplitCommandParser();
	
	private SplitCommandParams params;
	private String[] args;

	@SuppressWarnings("unused")
	private SplitCommand() {

	}

	public SplitCommand(final String... args) {
		this.args = args;
	}

	public void run() {
		build();
	}

	protected void build() {
		try {
		if (params == null) {
			parse();
		}
		validate();
		execute();
		} 
		catch (CommandParseException ex) {
			log.debug(ex.getMessage(), ex);
		}
		catch (CommandValidateException ex) {
			log.debug(ex.getMessage(), ex);
		}
		catch (CommandExecuteException ex) {
			log.debug(ex.getMessage(), ex);
		}
	}
	

	public void validate(){
		if(params==null){
			throw new NullPointerException("Can not get a valid input after parse!");
		}
		if(!FileOperator.isExistFile(params.getSrcFilePath())){
			throw new CommandValidateException("SrcFile doesn't exist "+params.getSrcFilePath());
		}
		List<FilePageRange> src=params.getDesFilePageRanges();
		for(FilePageRange fpr:src){
			if(FileOperator.isExistFile(fpr.getFilePath())){
				throw new CommandValidateException("DesFile exist or it's an invalid file path "+fpr.getFilePath());
			}
		}
	}

	public void parse(){
		params = PARASER.parse(args);
	}

	public void execute(){
		Document document = null;
		PdfReader reader = null;
		PdfCopy copy = null;
		List<FilePageRange> pgrList=null;
		
		try {
			reader = new PdfReader(params.getSrcFilePath());
			pgrList = params.getDesFilePageRanges();
			PDFOperator pdfOpt = new PDFOperator();
			for (FilePageRange range : pgrList) {
				FileOperator.createFile(range.getFilePath());
				document = new Document();
				copy = new PdfCopy(document, new BufferedOutputStream(
						new FileOutputStream(range.getFilePath())));
				document.open();
				
				List<PageRange> prList = range.getPageRangeList();
				if (range.isAllPages()) {
					// Reader reads all the page and copy to PdfCopy.
					pdfOpt.extractAll(copy, reader);
				} else {
					for (PageRange pr : prList) {
						pdfOpt.extract(copy, reader, pr.getStartIndex(), pr
								.getEndIndex());
					}
				}
				document.close();
			}
		} catch (IOException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		} catch (DocumentException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		} catch (PDFOperationException ex) {
			throw new CommandExecuteException(ex.getMessage(), ex);
		} finally {
			if (reader != null) {
				reader.close();
			}if(document!=null){
				document.close();
			}
		}
	}

	public void setParams(SplitCommandParams params) {
		this.params = params;
	}


}
